---
title: useReducer
---

import useReducer from '../../examples/files/hooks/useReducer.js'
import useStateSubValues from '../../examples/files/hooks/useStateSubValues.js'
import useStateObject from '../../examples/files/hooks/useStateObject.js'
import useStateInitializer from '../../examples/files/hooks/useStateInitializer.js'

<Author name="@msyleung" url="https://twitter.com/msyleung" />

The `useReducer` hook is similar to `useState`, but gives us a more structured approach for updating complex values.

We typically use `useReducer` when our state has multiple sub-values, e.g. an object containing keys that we want to update independently.

## API

The `useReducer` hook requires 2 arguments, and has an optional 3rd argument:

- `reducer` - a pure function that takes a state and an action, and returns a new state value based on the action
- `initialState` - any initial state value, just like `useState`
- `initializer` (optional) - this is uncommon, but we'll briefly introduce it later.

The `useReducer` hook returns the current state, and a `dispatch` function to update the state.

## Dispatch

The dispatch function takes an `action`, and calls the reducer to update the state.

In the example below, the initial state is `{color: 'black', pet: 'cat'}`. When we select `dog` from the dropdown, dispatch is called with `{type: types.PET, value: 'dog'}` as its argument. This argument gets passed to the reducer as `action`. Then the reducer follows the switch case logic `case types.PET` and returns the new state: the current color and the pet contained in the action, `{color: 'black', pet: 'dog'}`

> We typically use constants to identify the `type` for the switch case (e.g. `PET` or `COLOR`) to avoid typos and to make it easier to change in the future if needed.

<Example code={useReducer} />

## useState vs. useReducer

These hooks are conceptually similar: they both store state variables. So, when should we use one or the other?

Consider the example above. If we were to use `useState` in this scenario, what would it look like? One option would be two state variables:

<Example panes={['editor']} code={useStateSubValues} />

This option works well when our state variables are independent: e.g. changing the pet will never _also_ change the color, or vice versa. However, when we have multiple state variables that depend on one another, it can become challenging to keep everything in sync.

Another option would be a single object that we update manually:

<Example panes={['editor']} code={useStateObject} />

This option lets us update all state variables at once, making it easier to keep things in sync. This option works well when our state object is small, but as soon as it becomes larger, our code for updating the state will start taking up a lot of lines, making it harder to follow the logic of our component.

The `useReducer` hook essentially takes this second approach (a single state object), and provides a more structured API. We can then move our state-handling code outside of our component, so our component logic is clearer and our state logic can be tested independently. Additionally, if we want to allow children components to update the state, we can pass the `dispatch` function down into children as a prop, rather than creating a separate callback prop for every possible change a child might want to make.

In summary:

- Use `useState` for "simple" state, like JavaScript primitive values
- Use `useReducer` when there are different sub-values that depend on one another

## The third argument: Initializer

We mentioned this uncommon option briefly above: `useReducer` allows us to initialize state lazily with an `initializer` function. This is useful when creating the initial state is computationally expensive.

<Example panes={['editor']} code={useStateInitializer} />
